home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / music and sound / qtsndtween / qtsndtween.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  9.0 KB  |  323 lines

  1. //
  2. //    File:        QTSndTween.c
  3. //
  4. //    Contains:    Sound tweening support for QuickTime movies.
  5. //
  6. //    Written by:    Tim Monroe
  7. //                based largely on the tween sample code in the QuickTime 2.5 Developers Guide
  8. //                and the sample code QT3DTween.c.
  9. //
  10. //    Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  11. //
  12. //    Change History (most recent first):
  13. //
  14. //       <2>         05/26/98    rtm        set the time scale of the sound track media to that of the movie,
  15. //                                    using revised code from Peter Hoddie 
  16. //       <1>         04/10/98    rtm        first file; revised to personal coding style
  17. //       
  18. //
  19. // This sample shows how to modify an existing QuickTime movie so that the volume of its sound track
  20. // is gradually increased (or decreased) as the movie plays. We do this by adding a tween track to
  21. // the movie and linking the tween track to the existing sound track.
  22. // 
  23. // NOTES:
  24. //
  25. // ••• (1) •••
  26. // For complete information on creating tween media tracks, see the chapter "Tween Media Handler Components"
  27. // in the QuickTime 2.5 or 3.0 Developers Guide.
  28. //
  29. //
  30.  
  31. #include <FixMath.h>
  32. #include <Sound.h>
  33.  
  34. #include "QTSndTween.h"
  35.  
  36. // global variables
  37. // this variable determines what kind of tween data we add to the movie
  38.  
  39. Boolean                gTweenLoToHigh = true;        // do we start at no volume and end at full volume?
  40.  
  41.  
  42. //////////
  43. //
  44. // QTSndTween_OpenMovie
  45. // Have the user select a QuickTime movie.
  46. //
  47. //////////
  48.  
  49. Movie QTSndTween_OpenMovie (void)
  50. {
  51.     SFTypeList                    myTypeList;
  52.     StandardFileReply            myReply;
  53.     Movie                        myMovie = NULL;
  54.     short                        myResRefNum = 0;
  55.     OSErr                        myErr = noErr;
  56.  
  57.     // prompt the user for a movie
  58.     myTypeList[0] = MovieFileType;
  59.  
  60.     StandardGetFilePreview(NULL, 1, myTypeList, &myReply);
  61.     if (!myReply.sfGood)
  62.         goto bail;
  63.  
  64.     // open a movie file using the FSSpec and create a movie from that file
  65.     myErr = OpenMovieFile(&myReply.sfFile, &myResRefNum, 0);
  66.     if (myErr != noErr)
  67.         goto bail;
  68.             
  69.     myErr = NewMovieFromFile(&myMovie, myResRefNum, NULL, NULL, newMovieActive, NULL);
  70.     if (myErr != noErr)
  71.         goto bail;
  72.     
  73. bail:
  74.     // we're done with the movie file, so close it
  75.     if (myResRefNum != 0)
  76.         CloseMovieFile(myResRefNum);
  77.  
  78.     return(myMovie);
  79. }
  80.  
  81.  
  82. //////////
  83. //
  84. // QTSndTween_AddTweenTrackToMovie
  85. // Add a tween track to a QuickTIme movie.
  86. //
  87. //////////
  88.  
  89. OSErr QTSndTween_AddTweenTrackToMovie (void)
  90. {
  91.     Movie                        myMovie = NULL;
  92.     Track                        mySndTrack = NULL;
  93.     Track                        myTrack;
  94.     Media                        myMedia;
  95.     StandardFileReply            myReply;
  96.     SampleDescriptionHandle        mySampleDesc = NULL;
  97.     QTAtomContainer                mySample = NULL;
  98.     QTAtomContainer                myInputMap = NULL;
  99.     QTAtom                        myAtom = 0;
  100.     QTAtom                        myInputAtom = 0;
  101.     short                        myTweenData[2];
  102.     long                        myRefIndex;
  103.     TimeRecord                    myTimeRec;
  104.     OSErr                        myErr = noErr;
  105.  
  106.     //////////
  107.     //
  108.     // have the user select a movie
  109.     //
  110.     //////////
  111.  
  112.     myMovie = QTSndTween_OpenMovie();
  113.     if (myMovie == NULL)
  114.         goto bail;
  115.  
  116.     //////////
  117.     //
  118.     // get the (first) sound track from the movie
  119.     //
  120.     //////////
  121.     
  122.     mySndTrack = GetMovieIndTrackType(myMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
  123.     if (mySndTrack == NULL)
  124.         goto bail;
  125.  
  126.     //////////
  127.     //
  128.     // create the tween track and media, and a sample to contain the tween data
  129.     //
  130.     //////////
  131.  
  132.     // create the tween track and media
  133.     myTrack = NewMovieTrack(myMovie, 0, 0, kNoVolume);
  134.     myMedia = NewTrackMedia(myTrack, TweenMediaType, kTweenTimeScale, NULL, 0);
  135.  
  136.     // create a new sample; this sample will hold the tween data
  137.     myErr = QTNewAtomContainer(&mySample);
  138.     if (myErr != noErr)
  139.         goto bail;
  140.         
  141.     myTweenData[0] = gTweenLoToHigh ? EndianU16_NtoB(0)     : EndianU16_NtoB(512);
  142.     myTweenData[1] = gTweenLoToHigh ? EndianU16_NtoB(512)    : EndianU16_NtoB(0);
  143.         
  144.     // make a tween entry for that data;
  145.     // a tween entry is a parent atom that contains leaf atoms describing the tweening operation
  146.     myErr = QTSndTween_AddTweenEntryToSample(mySample, kSoundTweenID, kTweenTypeShort, &myTweenData, sizeof(myTweenData));
  147.     if (myErr != noErr)
  148.         goto bail;
  149.         
  150.     // create the sample description
  151.     mySampleDesc = (SampleDescriptionHandle)NewHandleClear(sizeof(SampleDescription));
  152.     if (mySampleDesc == NULL)
  153.         goto bail;
  154.     
  155.     (**mySampleDesc).descSize = sizeof(SampleDescription);
  156.  
  157.     // add the tween sample to the media
  158.     BeginMediaEdits(myMedia);
  159.  
  160.     // set the time scale of the media to that of the movie
  161.     myTimeRec.value.lo = GetTrackDuration(mySndTrack);
  162.     myTimeRec.value.hi = 0;
  163.     myTimeRec.scale = GetMovieTimeScale(myMovie);
  164.     ConvertTimeScale(&myTimeRec, GetMediaTimeScale(myMedia));
  165.  
  166.     myErr = AddMediaSample(myMedia, mySample, 0, GetHandleSize(mySample), myTimeRec.value.lo, (SampleDescriptionHandle)mySampleDesc, 1, 0, NULL);
  167.     if (myErr != noErr)
  168.         goto bail;
  169.  
  170.     EndMediaEdits(myMedia);
  171.  
  172.     // add the media to the track
  173.     InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1);
  174.  
  175.     // dispose of some things we no longer need
  176.     QTDisposeAtomContainer(mySample);
  177.     DisposeHandle((Handle)mySampleDesc);
  178.  
  179.     //////////
  180.     //
  181.     // create a link between the sound track and the tween track, and update the sound track's input map
  182.     //
  183.     //////////
  184.     
  185.     // first, create a new atom container
  186.     myErr = QTNewAtomContainer(&myInputMap);
  187.     if (myErr != noErr)
  188.         goto bail;
  189.     
  190.     // for *each* tween entry in the tween media sample,     
  191.     // create a link between the sound track and the tween track, and add an entry to the input map
  192.     
  193.     myErr = AddTrackReference(mySndTrack, myTrack, kTrackModifierReference, &myRefIndex);
  194.     if (myErr != noErr)
  195.         goto bail;
  196.         
  197.     myErr = QTSndTween_AddTweenEntryToInputMap(myInputMap, myRefIndex, kSoundTweenID, kTrackModifierTypeVolume, NULL);
  198.     if (myErr != noErr)
  199.         goto bail;
  200.  
  201.     // attach the input map to the sound media
  202.     myErr = SetMediaInputMap(GetTrackMedia(mySndTrack), myInputMap);
  203.     if (myErr != noErr)
  204.         goto bail;
  205.     
  206.     // dispose of the input map
  207.     QTDisposeAtomContainer(myInputMap);
  208.     
  209.     //////////
  210.     //
  211.     // finish up
  212.     //
  213.     //////////
  214.     
  215.     // save the new movie file
  216.     StandardPutFile("\pSave Movie as:", "\pNewMovie.mov", &myReply); 
  217.     if (myReply.sfGood) {
  218.         FlattenMovieData(myMovie, flattenAddMovieToDataFork, &myReply.sfFile, FOUR_CHAR_CODE('TVOD'), smSystemScript, createMovieFileDeleteCurFile);
  219.         myErr = GetMoviesError();
  220.     }
  221.  
  222. bail:
  223.     return(myErr);
  224. }
  225.  
  226.  
  227. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  228. //
  229. // Tween utilities.
  230. //
  231. // Use these functions add tween entries to samples or to add attributes to tween entries.
  232. //
  233. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  234.  
  235. //////////
  236. //
  237. // QTSndTween_AddTweenEntryToSample
  238. // Add a tween entry to the specified sample.
  239. //
  240. // A tween entry defines a set of values for a single tweening operation. A tween entry is a parent atom
  241. // whose children define the tween data type, the tween data, and additional attributes of the operation.
  242. //
  243. // The data specified in the theData parameter is assumed to be in big-endian format.
  244. //
  245. //////////
  246.  
  247. OSErr QTSndTween_AddTweenEntryToSample (QTAtomContainer theSample, QTAtomID theID, QTAtomType theType, void *theData, long theDataSize)
  248. {
  249.     OSErr                myErr = noErr;
  250.     QTAtom                myAtom;
  251.     
  252.     // create an entry for this tween in the sample
  253.     myErr = QTInsertChild(theSample, kParentAtomIsContainer, kTweenEntry, theID, 0, 0, NULL, &myAtom);
  254.     if (myErr != noErr)
  255.         goto bail;
  256.     
  257.     // set the type of this tween entry
  258.     theType = EndianU32_NtoB(theType);
  259.     myErr = QTInsertChild(theSample, myAtom, kTweenType, 1, 0, sizeof(theType), &theType, NULL);
  260.     if (myErr != noErr)
  261.         goto bail;
  262.     
  263.     // set the data for this tween entry
  264.     myErr = QTInsertChild(theSample, myAtom, kTweenData, 1, 0, theDataSize, theData, NULL);
  265.     
  266. bail:
  267.     return(myErr);
  268. }
  269.  
  270.  
  271. //////////
  272. //
  273. // QTSndTween_AddTweenEntryToInputMap
  274. // Add a tween entry to the specified input map.
  275. //
  276. //////////
  277.  
  278. OSErr QTSndTween_AddTweenEntryToInputMap (QTAtomContainer theInputMap, long theRefIndex, long theID, OSType theType, char *theName)
  279. {
  280.     QTAtom                myInputAtom;
  281.     OSErr                myErr = noErr;
  282.     
  283.     // add an entry to the input map
  284.     myErr = QTInsertChild(theInputMap, kParentAtomIsContainer, kTrackModifierInput, theRefIndex, 0, 0, NULL, &myInputAtom);
  285.     if (myErr != noErr)
  286.         goto bail;
  287.     
  288.     // add two child atoms to the parent atom;
  289.     // these atoms define the type of the modifier input and the ID of the tween entry atom
  290.     theType = EndianU32_NtoB(theType);
  291.     myErr = QTInsertChild(theInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(OSType), &theType, NULL);
  292.     if (myErr != noErr)
  293.         goto bail;
  294.  
  295.     theID = EndianU32_NtoB(theID);
  296.     myErr = QTInsertChild(theInputMap, myInputAtom, kInputMapSubInputID, 1, 0, sizeof(long), &theID, NULL);
  297.     if (myErr != noErr)
  298.         goto bail;
  299.         
  300.     // set the name of the input atom
  301.     if (theName != NULL) {
  302.         long        myLength = 1;
  303.         Ptr            myPtr = theName;
  304.         UInt16        *myShort;
  305.  
  306.         // determine the length of the name string
  307.         while (*myPtr++)
  308.             myLength++;
  309.  
  310.         // convert the name string to the proper endian format
  311.         myPtr = theName;
  312.         while (*myPtr) {
  313.             myShort = (UInt16 *)myPtr;
  314.             *myPtr = EndianU16_NtoB(*myShort);
  315.             myPtr = myPtr + 2;    // point to next word
  316.         }
  317.  
  318.         myErr = QTInsertChild(theInputMap, myInputAtom, kTrackModifierInputName, 1, 0, myLength, theName, NULL);
  319.     }
  320.     
  321. bail:
  322.     return(myErr);
  323. }